package com.yunpeng.aidevice.permission.service.impl;

import com.yunpeng.aidevice.common.vo.FunctionPermissionVO;
import com.yunpeng.aidevice.dao.service.IFunctionNodeService;
import com.yunpeng.aidevice.dao.service.IRoleService;
import com.yunpeng.aidevice.permission.service.IPermissionOuterService;
import com.yunpeng.cache.service.ISimpleMapCacheService;
import com.yunpeng.common.dto.Result;
import com.yunpeng.aidevice.dao.model.entity.FunctionNodeDO;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * PermissionOuterServiceImpl
 *
 * @author : Moore(hemw)
 * @date : 2020-04-07
 */
@Service
public class PermissionOuterServiceImpl implements IPermissionOuterService {

    /**
     * 日志对象
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(PermissionOuterServiceImpl.class);


    /**
     * 权限域
     */
    private static final String DOMAIN = "ai_device_permission";

    /**
     * 功能组
     */
    private static final String FUNCTION_TREE_GROUP = "functionTree";
    /**
     * 功能组
     */
    private static final String FUNCTION_MAP_GROUP = "functionMap";

    /**
     * 权限键
     */
    private static final String FUNCTION_KEY = "permission";

    @Resource
    private IFunctionNodeService functionNodeService;

    @Resource
    private ISimpleMapCacheService<List<FunctionPermissionVO>> functionPermissionTreeCacheService;

    @Resource
    private ISimpleMapCacheService<Map<String, FunctionPermissionVO>> functionPermissionMapCacheService;

    @Resource
    private IRoleService roleService;

    @Override
    /**
     * 获取功能权限树
     *
     * @param userCode 指定的用户代码
     * @return
     */
    public List<FunctionPermissionVO> getUsersPermissionTree(String userCode) {
        //先走缓存，再走实时
        Result<List<FunctionPermissionVO>> treeListResult = functionPermissionTreeCacheService.get(DOMAIN, FUNCTION_TREE_GROUP, FUNCTION_KEY, userCode, null);
        if (treeListResult == null || !treeListResult.isSuccess()) {
            return initTreeAndMapCache(userCode);
        }
        return treeListResult.getData();
    }

    @Override
    /**
     * 检查指定用户是否有指定功能权限操作权限
     *
     * @param nodeLocation 功能路径
     * @param userCode     用户代码
     * @return
     */
    public Boolean checkPermission(String nodeLocation, String userCode) {
        Result<Map<String, FunctionPermissionVO>> mapResult = functionPermissionMapCacheService.get(DOMAIN, FUNCTION_MAP_GROUP, FUNCTION_KEY, userCode, null);
        if (mapResult == null || !mapResult.isSuccess()) {
            initTreeAndMapCache(userCode);
        }
        //重新获取缓存
        mapResult = functionPermissionMapCacheService.get(DOMAIN, FUNCTION_MAP_GROUP, FUNCTION_KEY, userCode, null);
        if (mapResult == null || !mapResult.isSuccess() || mapResult.getData() == null || mapResult.getData().isEmpty()) {
            return false;
        }
        return mapResult.getData().containsKey(nodeLocation);
    }

    @Override
    /**
     * 清理用户权限缓存
     *
     * @param userCode 用户代码
     */
    public void clearUserCache(String userCode) {
        try {
            functionPermissionMapCacheService.remove(DOMAIN, FUNCTION_MAP_GROUP, FUNCTION_KEY, userCode);
            functionPermissionTreeCacheService.remove(DOMAIN, FUNCTION_TREE_GROUP, FUNCTION_KEY, userCode);
        } catch (Exception ex) {
            LOGGER.error("clear users permission cache error,", ex);
        }
    }

    @Override
    /**
     * 清理一批用户权限缓存
     *
     * @param userCodes 用户代码集合
     */
    public void clearUsersCache(List<String> userCodes) {
        if (userCodes != null) {
            try {
                for (String userCode : userCodes) {
                    functionPermissionMapCacheService.remove(DOMAIN, FUNCTION_MAP_GROUP, FUNCTION_KEY, userCode);
                    functionPermissionTreeCacheService.remove(DOMAIN, FUNCTION_TREE_GROUP, FUNCTION_KEY, userCode);
                }
            } catch (Exception ex) {
                LOGGER.error("clear users permission cache error,", ex);
            }
        }
    }

    @Override
    /**
     * 清理整个权限缓存map
     *
     * @param operatorCode 操作人代码
     */
    public void clearWholePermissionCache(String operatorCode) {
        try {
            functionPermissionMapCacheService.removeWholeMap(DOMAIN, FUNCTION_MAP_GROUP, FUNCTION_KEY, operatorCode);
            functionPermissionTreeCacheService.removeWholeMap(DOMAIN, FUNCTION_TREE_GROUP, FUNCTION_KEY, operatorCode);
        } catch (Exception ex) {
            LOGGER.error("clear hole users permission cache error,", ex);
        }
    }

    @Override
    /**
     * 验证用户编辑用户信息权限
     *
     * @param userCode
     * @param loginUserCode
     * @return
     */
    public Boolean checkUpdateAnotherUserInfo(String userCode, String loginUserCode) {
        return roleService.checkUpdateAnotherUserInfo(userCode, loginUserCode);
    }

    @Override
    /**
     * 验证用户是否具有某种角色
     *
     * @param roleCode 角色代码
     * @param userCode 用户代码
     * @return
     */
    public Boolean checkUserRole(String roleCode, String userCode) {
        return roleService.checkUserRole(roleCode, userCode);
    }


    //region 私有方法


    /**
     * 初始化功能权限树和功能权限map缓存
     *
     * @param userCode
     * @return
     */
    private List<FunctionPermissionVO> initTreeAndMapCache(String userCode) {
        List<FunctionNodeDO> functionNodeDOList = functionNodeService.getUserFunctionPermissionList(userCode);
        if (functionNodeDOList == null) {
            return new ArrayList<>();
        }
        Map<String, FunctionPermissionVO> functionPermissionMap = new HashMap<>(16);
        List<FunctionPermissionVO> treeList = recursiveGetTree(null, functionNodeDOList, functionPermissionMap);
        if (treeList.isEmpty()) {
            return new ArrayList<>();
        }
        //存入缓存，设置10分钟有效时间
        functionPermissionTreeCacheService.put(DOMAIN, FUNCTION_TREE_GROUP, FUNCTION_KEY, userCode, treeList, 10L);
        //存入缓存，设置10分钟有效时间
        functionPermissionMapCacheService.put(DOMAIN, FUNCTION_MAP_GROUP, FUNCTION_KEY, userCode, functionPermissionMap, 10L);
        return treeList;
    }

    /**
     * 递归组装功能权限树
     *
     * @param parentNode
     * @param list
     * @return
     */
    private List<FunctionPermissionVO> recursiveGetTree(FunctionNodeDO parentNode, List<FunctionNodeDO> list, Map<String, FunctionPermissionVO> functionPermissionMap) {
        //获取子集节点和其他节点
        List<FunctionNodeDO> currentSubList = new ArrayList<>();
        List<FunctionNodeDO> removeSubList = new ArrayList<>();
        boolean isRoot = parentNode == null;
        for (FunctionNodeDO functionNodeDO : list) {
            if (isRoot) {
                if (StringUtils.isBlank(functionNodeDO.getParentCode())) {
                    currentSubList.add(functionNodeDO);
                } else {
                    removeSubList.add(functionNodeDO);
                }
            } else {
                if (parentNode.getCode().equalsIgnoreCase(functionNodeDO.getParentCode())) {
                    currentSubList.add(functionNodeDO);
                } else {
                    removeSubList.add(functionNodeDO);
                }
            }
        }
        List<FunctionPermissionVO> result = new ArrayList<>();
        for (FunctionNodeDO functionNodeDO : currentSubList) {
            FunctionPermissionVO functionPermissionVO = new FunctionPermissionVO();
            functionPermissionVO.setNodeLocation(functionNodeDO.getUrl());
            functionPermissionVO.setNodeName(functionNodeDO.getName());
            functionPermissionVO.setNodeCode(functionNodeDO.getCode());
            functionPermissionVO.setFolder(functionNodeDO.getFolder());
            functionPermissionVO.setChildNodes(recursiveGetTree(functionNodeDO, removeSubList, functionPermissionMap));
            if (functionPermissionVO.getChildNodes().isEmpty() && functionNodeDO.getFolder()) {
                continue;
            }
            functionPermissionMap.put(functionNodeDO.getUrl(), functionPermissionVO);
            result.add(functionPermissionVO);
        }
        return result;
    }

    //endregion

}
